package com.zhuoyue.biz.core.api.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhuoyue.biz.core.api.dao.*;
import com.zhuoyue.biz.core.api.domain.*;
import com.zhuoyue.biz.core.api.dto.localscene.*;
import com.zhuoyue.biz.core.api.dto.rep.LocalSceneRepDTO;
import com.zhuoyue.common.exception.ErrorType;
import com.zhuoyue.common.exception.ZyServerException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;

import org.springframework.transaction.annotation.Transactional;

/**
 * @author Administrator
 */
@Service("localSceneService")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@Slf4j
public class LocalSceneService extends ServiceImpl<LocalSceneDao, LocalSceneDO> {
    private final DeviceDao deviceDao;
    private final LocalSceneDao localSceneDao;
    private final AutomateDao automateDao;
    private final GatewayDao gatewayDao;
    private final LocalSceneZigbeeDeviceRelationMapper localSceneZigbeeDeviceRelationMapper;
    private final LocalSceneInfraredDeviceRelationMapper localSceneInfraredDeviceRelationMapper;
    private final LocalSceneGatewayRelationMapper localSceneGatewayRelationMapper;
    private final LocalSceneGroupRelationMapper localSceneGroupRelationMapper;
    private final CompositeSceneRelationMapper compositeSceneRelationMapper;
    private static final int HARDWARE_VERSION_NUMBER_2111 = 2111;


    public List<LocalSceneRepDTO> getLocalSceneListByHomeId(String homeId) {


        List<LocalSceneDO> list = localSceneDao.selectList(Wrappers.<LocalSceneDO>lambdaQuery().eq(LocalSceneDO::getHomeId, homeId).orderByAsc(LocalSceneDO::getCreateTime));
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }
        List<LocalSceneRepDTO> dtoList = new ArrayList<>();
        for (LocalSceneDO localSceneDO : list) {
            LocalSceneRepDTO localSceneRepDTO = new LocalSceneRepDTO();
            //进行数据合并
            String exState = getLocalSceneExDevice(localSceneDO.getId());
            localSceneDO.setExecuteDeviceState(exState);
            BeanUtils.copyProperties(localSceneDO, localSceneRepDTO);
            dtoList.add(localSceneRepDTO);
        }
        return dtoList;
    }

    @Transactional(rollbackFor = Exception.class)
    public LocalSceneDO updateLocalSceneById(LocalSceneDO localScene) {
        //先修改基本信息
        LocalSceneDO build = LocalSceneDO.builder().homeId(localScene.getHomeId()).gatewayMac(localScene.getGatewayMac())
                .fixedTime(localScene.getFixedTime()).name(localScene.getName()).imgUrl(localScene.getImgUrl()).first(localScene.getFirst())
                .build();
        build.setId(localScene.getId());
        int count = localSceneDao.updateById(build);
        if (count < 1) {
            throw new ZyServerException(ErrorType.INVALID_PARAMS.getCode(), "本地场景修改失败");
        }
        removeSceneAndParam(localScene.getId());
        return localSceneDeviceClass(localScene);
    }

    public List<ShowSceneDO> getShowLocalSceneListByHomeId(String homeId) {

        List<LocalSceneDO> list = localSceneDao.selectList(Wrappers.<LocalSceneDO>lambdaQuery()
                .eq(LocalSceneDO::getHomeId, homeId).eq(LocalSceneDO::getIsShow, 1).orderByAsc(LocalSceneDO::getCreateTime));

        if (CollectionUtils.isEmpty(list)) {
            throw new ZyServerException(ErrorType.result_not_exist.getCode(), "用户未设置首页展示的本地场景！");
        }

        List<ShowSceneDO> listDto = new ArrayList<>();
        list.stream().forEach(localSceneDo -> {
            ShowSceneDO localSceneRepDTO = new ShowSceneDO();
            BeanUtils.copyProperties(localSceneDo, localSceneRepDTO);
            listDto.add(localSceneRepDTO);
        });
        return listDto;
    }

    public LocalSceneRepDTO getLocalSceneById(String id) {
        LocalSceneDO localSceneDO = localSceneDao.selectById(id);
        String localScene1 = getLocalSceneExDevice(id);
        localSceneDO.setExecuteDeviceState(localScene1);
        LocalSceneRepDTO localSceneRepDTO = new LocalSceneRepDTO();
        BeanUtils.copyProperties(localSceneDO, localSceneRepDTO);
        localSceneRepDTO.setCreateTime(localSceneDO.getCreateTime());
        return localSceneRepDTO;
    }

    /**
     * 2021/1/4 修改本地场景和自动化总共46
     *
     * @param localScene
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public LocalSceneDO addLocalScene(LocalSceneDO localScene) {
        List<Integer> codeList = localSceneDao.selectLocalSceneCodeByGatewayMac(localScene.getGatewayMac());
        List<AutomateDO> autoCodeList = automateDao.selectList(Wrappers.<AutomateDO>lambdaQuery()
                .eq(AutomateDO::getGatewayMac, localScene.getGatewayMac()));
        List<Integer> autoList = autoCodeList.stream().map(automateDo -> automateDo.getCode()).collect(Collectors.toList());
        codeList.addAll(autoList);
        GatewayDO gatewayDO = gatewayDao.selectOne(Wrappers.<GatewayDO>lambdaQuery()
                .eq(GatewayDO::getZigbeeMac, localScene.getGatewayMac()));
        int countNumber = 46;
        String hardwareVersionNumber = gatewayDO.getHardwareVersionNumber();
        if (StringUtils.isNotEmpty(hardwareVersionNumber) && Integer.parseInt(hardwareVersionNumber) >= HARDWARE_VERSION_NUMBER_2111) {
            countNumber = 98;
        }
        int code = 0;
        if (CollectionUtils.isEmpty(codeList)) {
            code = 1;
        } else {
            if (codeList.size() >= countNumber) {
                throw new ZyServerException(ErrorType.INVALID_PARAMS.getCode(), "本地场景自动化已达上限" + countNumber + "个");
            } else {
                Map<Integer, Integer> map = new HashMap<>(5);
                for (Integer c : codeList) {
                    if (null != c) {
                        map.put(c, c);
                    }
                }
                for (int i = 1; i < countNumber + 1; i++) {
                    if (null == map.get(i)) {
                        code = i;
                        break;
                    }
                }
            }
        }

        if (code < 1 || code > countNumber + 1) {
            throw new ZyServerException(ErrorType.INVALID_PARAMS.getCode(), "本地场景编号错误");
        }

        localScene.setCode(code);

        int count = localSceneDao.insert(localScene);

        if (count < 1) {
            throw new ZyServerException(ErrorType.INVALID_PARAMS.getCode(), "本地场景新增失败");
        }
        return localSceneDeviceClass(localScene);
    }

    /**
     * 获取场景或者自动化执行设备的执行信息
     *
     * @param id
     * @return 场景或自动化执行设备信息的jsonString信息
     */
    public String getLocalSceneExDevice(String id) {
        List<Object> list = new ArrayList<>();

        /**
         * 网关
         */
        QueryWrapper<LocalSceneGatewayRelation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(LocalSceneGatewayRelation.COL_SCENE_ID, id);
        queryWrapper.orderByAsc(LocalSceneGatewayRelation.SORT);
        List<GateWayDeviceDTO> localSceneGatewayRelations = localSceneGatewayRelationMapper.selectListById(queryWrapper);

        if (CollectionUtils.isNotEmpty(localSceneGatewayRelations)) {
            for (GateWayDeviceDTO gateWayDeviceDTO : localSceneGatewayRelations) {
                gateWayDeviceDTO.setTitleDes(gateWayDeviceDTO.getHomeName() + "-" + gateWayDeviceDTO.getTitleDes());
                Map mapTypes = JSON.parseObject((String) gateWayDeviceDTO.getControlParam());
                gateWayDeviceDTO.setControlParam(mapTypes);
                list.add(gateWayDeviceDTO);
            }
        }


        /**
         * 红外设备信息组合
         */
        QueryWrapper<LocalSceneInfraredDeviceRelation> infraredDeviceRelationQueryWrapper = new QueryWrapper<>();
        infraredDeviceRelationQueryWrapper.eq(LocalSceneInfraredDeviceRelation.COL_SCENE_ID, id);
        infraredDeviceRelationQueryWrapper.orderByAsc(LocalSceneInfraredDeviceRelation.COL_SORT);
        List<InfraredDeviceDTO> localSceneInfraredDeviceRelations = localSceneInfraredDeviceRelationMapper.selectListById(infraredDeviceRelationQueryWrapper);

        if (CollectionUtils.isNotEmpty(localSceneInfraredDeviceRelations)) {
            for (InfraredDeviceDTO infraredDeviceDTO : localSceneInfraredDeviceRelations) {
                Map mapTypes = JSON.parseObject((String) infraredDeviceDTO.getControlParam());
                List<JSONObject> lists = null;
                try {
                    JSONArray jsonArray = JSONArray.fromObject(infraredDeviceDTO.getChildExecuteDevices());
                    lists = new ArrayList<>();
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JSONObject jsonObject = jsonArray.getJSONObject(i);
                        lists.add(jsonObject);
                    }
                } catch (Exception e) {
                    System.out.println("getChildExecuteDevices " + infraredDeviceDTO.getChildExecuteDevices());
                }
                //中央空调控制器专用
                if (StringUtils.equals("0FE60207", infraredDeviceDTO.getIdentify())) {
                    String deviceMac = (String) mapTypes.get("deviceMac");
                    String name = deviceDao.selectOne(Wrappers.<DeviceDO>lambdaQuery()
                            .eq(DeviceDO::getZigbeeMac, deviceMac)).getName();
                    infraredDeviceDTO.setTitleDes(name + "-" + infraredDeviceDTO.getDeviceName());
                }
                //普通红外设备专用
                else {
                    infraredDeviceDTO.setTitleDes(StringUtils.isEmpty(infraredDeviceDTO.getRoomName()) ? infraredDeviceDTO.getDeviceName() : infraredDeviceDTO.getRoomName() + "-" + infraredDeviceDTO.getDeviceName());
                }

                infraredDeviceDTO.setControlParam(mapTypes);
                infraredDeviceDTO.setChildExecuteDevices(lists);
                list.add(infraredDeviceDTO);
            }
        }

        /**
         * zigbee设备信息组合
         */
        QueryWrapper<LocalSceneZigbeeDeviceRelation> zigbeeDeviceRelationQueryWrapper = new QueryWrapper<>();
        zigbeeDeviceRelationQueryWrapper.eq(LocalSceneZigbeeDeviceRelation.COL_SCENE_ID, id);
        zigbeeDeviceRelationQueryWrapper.orderByAsc(LocalSceneZigbeeDeviceRelation.COL_SORT);
        List<ZigbeeDeviceDTO> localSceneZigbeeDeviceRelations = localSceneZigbeeDeviceRelationMapper.selectListById(zigbeeDeviceRelationQueryWrapper);

        if (CollectionUtils.isNotEmpty(localSceneZigbeeDeviceRelations)) {
            for (ZigbeeDeviceDTO zigbeeDeviceDTO : localSceneZigbeeDeviceRelations) {
                Map mapTypes = JSON.parseObject((String) zigbeeDeviceDTO.getControlParam());
                if (zigbeeDeviceDTO.getChildExecuteDevices() != null && zigbeeDeviceDTO.getChildExecuteDevices() != "") {
                    JSONArray jsonArray = JSONArray.fromObject(zigbeeDeviceDTO.getChildExecuteDevices());
                    List<JSONObject> lists = new ArrayList<>();
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JSONObject jsonObject = jsonArray.getJSONObject(i);
                        lists.add(jsonObject);
                    }
                    zigbeeDeviceDTO.setChildExecuteDevices(lists);
                } else {
                    mapTypes.remove("childExecuteDevices");
                }
                zigbeeDeviceDTO.setTitleDes(StringUtils.isEmpty(zigbeeDeviceDTO.getRoomName()) ? zigbeeDeviceDTO.getDeviceName() : zigbeeDeviceDTO.getRoomName() + "-" + zigbeeDeviceDTO.getDeviceName());
                zigbeeDeviceDTO.setControlParam(mapTypes);
                list.add(zigbeeDeviceDTO);
            }
        }

        /**
         * 组合场景信息组合
         */
        QueryWrapper<CompositeSceneRelation> compositeSceneRelationQueryWrapper = new QueryWrapper<>();
        compositeSceneRelationQueryWrapper.eq(CompositeSceneRelation.COL_SCENE_ID, id);
        compositeSceneRelationQueryWrapper.orderByAsc(CompositeSceneRelation.COL_SORT);
        List<CompositeSceneRelationDTO> compositescenerelationDtos = compositeSceneRelationMapper.selectListById(compositeSceneRelationQueryWrapper);

        if (CollectionUtils.isNotEmpty(compositescenerelationDtos)) {
            compositescenerelationDtos.stream().forEach(listStr -> {
                Map mapTypes = JSON.parseObject((String) listStr.getControlParam());
                listStr.setControlParam(mapTypes);
                list.add(listStr);
            });
        }
        /**
         * 群组
         */
        QueryWrapper<LocalSceneGroupRelation> sceneGroupRelationQueryWrapper = new QueryWrapper<>();
        sceneGroupRelationQueryWrapper.eq(LocalSceneGroupRelation.COL_SCENE_ID, id);
        sceneGroupRelationQueryWrapper.orderByAsc(LocalSceneGroupRelation.COL_SORT);
        List<GroupDTO> dtos = localSceneGroupRelationMapper.selectListById(sceneGroupRelationQueryWrapper);

        if (CollectionUtils.isNotEmpty(dtos)) {
            dtos.forEach(groupDTO -> {
                Map mapTypes = JSON.parseObject((String) groupDTO.getControlParam());
                groupDTO.setControlParam(mapTypes);
                groupDTO.setDeviceType("Group");
                list.add(groupDTO);
            });
        }
        String s = JSON.toJSONString(list);
        return s;
    }


    //场景添加分离设备信息

    @Transactional(rollbackFor = Exception.class)
    public LocalSceneDO localSceneDeviceClass(LocalSceneDO localScene) {
        String localSceneId = localScene.getId();
        //场景添加完成后获取当前场景ID,并且进行设备类型分类
        sceneOrAuto(localScene.getId(), localScene.getExecuteDeviceState());
        //查询场景
        LocalSceneDO localSceneDO = localSceneDao.selectById(localSceneId);
        String exState = getLocalSceneExDevice(localSceneId);
        localSceneDO.setExecuteDeviceState(exState);
        return localSceneDO;
    }


    /**
     * 添加场景和自动化
     *
     * @param id
     * @param excuteDeviceState
     */
    @Transactional(rollbackFor = Exception.class)
    public void sceneOrAuto(String id, String excuteDeviceState) {
        //场景添加完成后获取当前场景ID,并且进行设备类型分类
        JSONArray jsonArray = JSONArray.fromObject(excuteDeviceState);
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject device = jsonArray.getJSONObject(i);

            String cmd = device.get("cmd").toString();

            String deviceId = device.get("deviceId").toString();
            String purpose = device.get("purpose").toString();
            String stateDes = device.get("stateDes") != null ? device.get("stateDes").toString() : null;
            String controlParam = device.get("controlParam").toString();
            String identify = device.get("identify") != null ? device.get("identify").toString() : null;
            String state = device.get("state") != null ? device.get("state").toString() : null;
            String imgName = device.get("imgName") != null ? device.get("imgName").toString() : null;
            String deleyTimeMinute = device.get("deleyTimeMinute") != null ? device.get("deleyTimeMinute").toString() : null;
            String deleyTimeSecond = device.get("deleyTimeSecond") != null ? device.get("deleyTimeSecond").toString() : null;
            switch (device.get("deviceType").toString()) {
                //红外设备
                case "INFRARED":
                    LocalSceneInfraredDeviceRelation build = LocalSceneInfraredDeviceRelation.builder().cmd(cmd).infraredId(deviceId).
                            childExecuteDevices(device.get("childExecuteDevices") == null ? "" : device.get("childExecuteDevices").toString()).controlParam(controlParam).sceneId(id)
                            .identify(identify).imgName(imgName).purpose(purpose).state(Integer.parseInt(state)).stateDes(stateDes).deleyTimeMinute(deleyTimeMinute).deleyTimeSecond(deleyTimeSecond).sort(i)
                            .build();
                    int insert = localSceneInfraredDeviceRelationMapper.insert(build);
                    if (insert < 1) {
                        throw new ZyServerException(ErrorType.Service_Fail.getCode(), "场景中添加红外设备失败");
                    }
                    break;
                case "Gateway_Voice":
                    //网关设备
                case "Gateway":
                    LocalSceneGatewayRelation localSceneGatewayRelation = LocalSceneGatewayRelation.builder().cmd(cmd).sceneId(id)
                            .gatewayId(deviceId).controlParam(controlParam).purpose(purpose).state(state).stateDes(stateDes)
                            .deviceType(device.get("deviceType").toString()).sort(i).build();
                    int insert1 = localSceneGatewayRelationMapper.insert(localSceneGatewayRelation);
                    if (insert1 < 1) {
                        throw new ZyServerException(ErrorType.Service_Fail.getCode(), "场景中添加网关设备失败");
                    }
                    break;
                //场景
                case "Scene":
                    CompositeSceneRelation compositeSceneRelation = CompositeSceneRelation.builder().cmd(cmd).sceneId(id).childScene(deviceId)
                            .controlParam(controlParam).purpose(purpose).state(Integer.parseInt(state)).stateDes(stateDes).sort(i).build();
                    try {
                        int insert3 = compositeSceneRelationMapper.insert(compositeSceneRelation);
                        if (insert3 < 1) {
                            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "组合场景添加失败");
                        }
                    } catch (Exception e) {
                        if (e instanceof DataIntegrityViolationException) {
                            System.out.println(e.getMessage());
                            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "组合场景中未找到对应场景信息，组合场景添加失败");
                        }
                        throw new ZyServerException(ErrorType.INVALID_PARAMS.getCode(), "参数不正确");
                    }

                    break;
                //群组
                case "Group":
                    try {
                        String deleyTimeMinuteGroup = device.get("deleyTimeMinute") != null ? device.get("deleyTimeMinute").toString() : null;
                        String deleyTimeSecondGroup = device.get("deleyTimeSecond") != null ? device.get("deleyTimeSecond").toString() : null;
                        LocalSceneGroupRelation sceneGroupRelation = LocalSceneGroupRelation.builder().sceneId(id).deviceId(deviceId).deleyTimeMinute(deleyTimeMinuteGroup)
                                .deleyTimeSecond(deleyTimeSecondGroup).stateDes(stateDes).cmd(cmd).purpose(purpose).imgName(imgName).controlParam(controlParam).sort(i)
                                .state(Integer.parseInt(state)).build();
                        int insert4 = localSceneGroupRelationMapper.insert(sceneGroupRelation);
                        if (insert4 < 1) {
                            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "组合场景添加失败");
                        }
                    } catch (Exception e) {
                        if (e instanceof DataIntegrityViolationException) {
                            System.out.println(e.getMessage());
                            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "未找到群组,请检查群组就是否已添加");
                        }
                        throw new ZyServerException(ErrorType.INVALID_PARAMS.getCode(), "参数不正确");
                    }
                    break;
                default://默认是zigbee设备
                    LocalSceneZigbeeDeviceRelation localSceneZigbeeDeviceRelation = LocalSceneZigbeeDeviceRelation
                            .builder()
                            .cmd(cmd).purpose(purpose).deviceId(deviceId).stateDes(stateDes).controlParam(controlParam)
                            .deviceType(device.get("deviceType").toString()).state(state).deleyTimeMinute(deleyTimeMinute)
                            .deleyTimeSecond(deleyTimeSecond).identify(identify).sceneId(id).sort(i)
                            .build();
                    if (device.get("childExecuteDevices") != null && device.get("childExecuteDevices") != "") {
                        localSceneZigbeeDeviceRelation.setChildExecuteDevices(device.get("childExecuteDevices").toString());
                    }
                    try {
                        int insert2 = localSceneZigbeeDeviceRelationMapper.insert(localSceneZigbeeDeviceRelation);
                        if (insert2 < 1) {
                            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "场景中添加zigbee设备失败");
                        }
                    } catch (Exception e) {
                        if (e instanceof DataIntegrityViolationException) {
                            System.out.printf(e.getMessage());
                            throw new ZyServerException(ErrorType.Service_Fail.getCode(), "未找到场景中的设备,请确认已添加此设备");
                        }
                        throw new ZyServerException(ErrorType.INVALID_PARAMS.getCode(), "参数不正确");
                    }
                    break;
            }
        }
    }

    public void removeSceneAndParam(String id) {
        localSceneZigbeeDeviceRelationMapper.delete(Wrappers.<LocalSceneZigbeeDeviceRelation>lambdaQuery()
                .eq(LocalSceneZigbeeDeviceRelation::getSceneId, id));

        localSceneGatewayRelationMapper.delete(Wrappers.<LocalSceneGatewayRelation>lambdaQuery()
                .eq(LocalSceneGatewayRelation::getSceneId, id));

        localSceneInfraredDeviceRelationMapper.delete(Wrappers.<LocalSceneInfraredDeviceRelation>lambdaQuery()
                .eq(LocalSceneInfraredDeviceRelation::getSceneId, id));

        compositeSceneRelationMapper.delete(Wrappers.<CompositeSceneRelation>lambdaQuery()
                .eq(CompositeSceneRelation::getSceneId, id));

        localSceneGroupRelationMapper.delete(Wrappers.<LocalSceneGroupRelation>lambdaQuery()
                .eq(LocalSceneGroupRelation::getSceneId, id));
    }


    /**
     * 创建两个空场景
     *
     * @param homeId
     */
    public void createTwoNullScenes(String homeId) {
        // 默认两个场景
        List<LocalSceneDO> localSceneDos = localSceneObj(homeId, "回家,离家", "scene_01,scene_02");
        boolean b1 = saveBatch(localSceneDos);
        if (!b1) {
            throw new ZyServerException(ErrorType.OBJECT_NOT_FOUND);
        }
    }


    /**
     * 场景添加
     *
     * @param homeId
     * @param name
     * @param img
     * @return
     */
    private List<LocalSceneDO> localSceneObj(String homeId, String name, String img) {
        String[] split = name.split(",");
        String[] split1 = img.split(",");
        List<LocalSceneDO> localSceneDos = new ArrayList<>();
        for (int i = 0; i < split.length; i++) {
            LocalSceneDO localScene = new LocalSceneDO();
            localScene.setHomeId(homeId);
            localScene.setName(split[i]);
            localScene.setImgUrl(split1[i]);
            localScene.setIsShow(1);
            localScene.setSceneType(0);
            localScene.setCode(i + 1);
            localSceneDos.add(localScene);
        }
        return localSceneDos;
    }

}
